-- 战斗模块
local ConfigLoader = require("config.loader")
local Settings = require("config.settings")
local config = ConfigLoader.load(Settings.CURRENT_GAME)
local logger = require "utils.logger"
local stateManager = require "utils.state_manager"
local movement = require "modules.movement"
local combat = require "modules.combat"
local window = require "modules.window"
local tslib = require "TSLib"

local Map = {}

-- 根据多点比色判断是否打开地图
function Map.isOpenMap()
    return multiColor(config.MAP.IS_OPEN_MAP_COLORS)
end

-- 打开地图
function Map.openMap()
    if not Map.isOpenMap() then
        tap(config.MAP.OPEN_MAP_COORDS[1], config.MAP.OPEN_MAP_COORDS[2])
        mSleep(1500)
    end
    logger.info("打开地图")
end

-- 关闭地图
function Map.closeMap()
    logger.info("关闭地图")
    if Map.isOpenMap() then
        tap(config.MAP.CLOSE_MAP_COORDS[1], config.MAP.CLOSE_MAP_COORDS[2])
        mSleep(800)
    end
end

-- 获取地图上自己的位置
function Map.getMyPosition()
    local x, y = findMultiColorInRegionFuzzy(0xffff00, "-4|0|0xf9f902,3|0|0xfafa02,0|3|0xfafa01,0|-4|0xf7f702", 90, 283,
        160, 1316, 779, { orient = 2 })
    if x ~= -1 then
        logger.info(string.format("我的位置为:%d,%d", x, y))
    end
    return x, y
end

-- 获取地图上bs的位置白色图标
function Map.getBsPosition(bsx, bsy)
    local x, y = findMultiColorInRegionFuzzy(0xcdc6c1, "6|-2|0xddd9d5,17|-1|0xf1eee9,12|9|0xe9e5e1,1|8|0xe2ddd9", 90, bsx,
        bsy,
        bsx + 100, bsy + 100, { orient = 2, max_miss = 2 })
    if x ~= -1 then
        logger.info(string.format("bs位置为:%d,%d", x, y))
    end
    return x, y
end

-- 获取地图上bs被击杀的图标
function Map.isBsDeadPicPosition(bsx, bsy)
    local x, y = findMultiColorInRegionFuzzy(0xe3003a, "1|0|0xed0338,1|1|0xf01444,0|1|0xe5003b,0|2|0xe60140,1|2|0xee0632",
        90, bsx - 20, bsy - 20, bsx + 20, bsy + 20, { orient = 2, max_miss = 2 })
    if x ~= -1 then
        return true
    end
    return false
end

-- 获取地图上红色名字bs的位置
function Map.getBsRedNamePosition()
    local x, y = findMultiColorInRegionFuzzy(0xff0000, "", 90, 285, 227, 1056, 786, { orient = 2 })
    if x ~= -1 then
        logger.info(string.format("bs名称位置为:%d,%d", x, y))
    end
    return x, y
end

-- 通过地图上红色的红字限制查询范围，查询地图上bs的白色图标位置
function Map.getBsWhitePicPosition(bsx, bsy)
    -- 如果bsx和bsy有值，说明bs位置是固定的，直接返回bs位置
    if bsx and bsy then
        return bsx, bsy
    end
    if x ~= -1 and y ~= -1 then
        local x, y = Map.getBsRedNamePosition()
        local bs_x, bs_y = Map.getBsPosition(x, y)
        if bs_x ~= -1 and bs_y ~= -1 then
            return bs_x, bs_y
        end
    end
    logger.info("未找到bs白色图标")
    return -1, -1
end

-- 判断地图上的自己的位置与传入坐标，x和y坐标相差10个像素的附近
function Map.isMyPositionNear(x, y, threshold)
    threshold = threshold or 15
    local my_x, my_y = Map.getMyPosition()
    if my_x ~= -1 and my_y ~= -1 then
        if math.abs(my_x - x) <= threshold and math.abs(my_y - y) <= threshold then
            return true
        end
    end
    return false
end

-- 使用随机石飞到离bs附近150的位置
function Map.useRandomStoneToBs(bsx, bsy, flag)
    flag = flag or false
    if not flag then
        return
    end
    -- 循环判断使用随机石，并添加最多20次
    local count = 0
    while count < 20 do
        if Map.isMyPositionNear(bsx, bsy, 100) then
            logger.info("已到达bs附近100码的位置")
            break
        end
        count = count + 1
        Map.useRandomStoneOnMap()
        mSleep(1500)
    end
    tap(bsx, bsy)
end

-- 测试寻找bs位置，并移动到指定位置，开启攻击
-- 封装测试方法，用于寻找bs位置并移动到该位置后开启自动攻击
function Map.findBsAndGoto(bsx, bsy)
    Map.openMap()
    local x, y = Map.getBsWhitePicPosition(bsx, bsy)
    if x ~= -1 and y ~= -1 then
        Map.useRandomStoneToBs(x, y)
        tap(x, y)
        local retry = 0
        while not Map.isMyPositionNear(x, y) and retry < 100 do
            logger.info("等待移动到目标位置")
            mSleep(5000)
            retry = retry + 1
        end
        if retry >= 100 then
            logger.info("未到达目标位置")
            return false
        end
        logger.info("已到达目标位置")
        Map.closeMap()
        return true
    else
        logger.info("bs已被击杀")
        Map.closeMap()
        return false
    end
end

-- 用于寻找bs位置并飞到该位置后开启自动攻击
function Map.findBsAndFly(bsx, bsy)
    Map.openMap()
    tap(bsx, bsy)
    mSleep(800)
    tap(config.MAP.USE_FLY_BUN_COORDS[1], config.MAP.USE_FLY_BUN_COORDS[2])
    local retry = 0
    while not multiColor(config.MAP.USE_FLY_ENTRY_COLORS) and retry < 20 do
        logger.info("等待出现飞鞋确认")
        mSleep(3000)
        retry = retry + 1
    end
    if retry >= 20 then
        logger.info("未到达目标位置")
        return false
    end
    tap(config.MAP.USE_FLY_ENTRY_COLORS[1][1], config.MAP.USE_FLY_ENTRY_COLORS[1][2])
    logger.info("已到达目标位置")
    Map.closeMap()
    combat.startAutoAttack()
    return true
end

-- 打开地图使用随机石
function Map.useRandomStoneOnMap()
    tap(config.MAP.USE_RANDOM_STONE_COORDS[1], config.MAP.USE_RANDOM_STONE_COORDS[2])
end

-- 打开地图使用回城石
function Map.useBackStoneOnMap()
    tap(config.MAP.USE_BACK_STONE_COORDS[1], config.MAP.USE_BACK_STONE_COORDS[2])
end

-- 地图位置验证函数（支持任意地图）
function Map.verifyMapLocation(color_points)
    return multiColor(color_points)
end

-- 通过多点比色进入地图的通用函数
function Map.enterMap(map_name)
    local map_cfg = config.BOSS_MAPS[map_name]
    logger.info("运行进入地图脚本")
    local max_limit = 0;
    while true do
        local success, err = pcall(function()
            if not Map.verifyMapLocation(map_cfg.MAP_NAME_POINT) then
                movement.useTownStone()
                movement.dragDirection(map_cfg.DRAG_DIRECTION, map_cfg.DRAG_TIME)
                mSleep(1000)

                local attempts = 0
                local max_attempts = config.COLOR_MATCH.ATTEMPTS or 3
                while attempts < max_attempts do
                    local x, y = findMultiColorInRegionFuzzy(map_cfg.NPC_COLOR[1], map_cfg.NPC_COLOR[2], 90, 0, 0, 1600,
                        900, { orient = 2, main = 0x202020, list = 0x202020 })
                    if x ~= -1 then
                        logger.info(string.format("第%d次比色成功", attempts + 1))
                        logger.info(string.format("坐标为:%d,%d", x, y))
                        movement.clickSeries(map_cfg.BUTTONS)
                        if Map.verifyMapLocation(map_cfg.MAP_NAME_POINT) then
                            logger.info("已到达" .. map_name .. "地图")
                            combat.startAutoAttack()
                            return true
                        else
                            movement.useTownStone()
                            movement.dragDirection(map_cfg.DRAG_DIRECTION, map_cfg.DRAG_TIME)
                            mSleep(1000)
                        end
                    else
                        attempts = attempts + 1
                        logger.info(string.format("比色失败，已尝试%d次", attempts))
                        mSleep(config.COLOR_MATCH.RETRY_INTERVAL or 1000)
                    end
                end
                logger.info(string.format("未进入%s地图", map_name))
            else
                logger.info("当前已在" .. map_name .. "中")
                return true
            end
        end)
        if not success then
            logger.error("地图任务执行出错: " .. tostring(err))
            logger.error("错误堆栈: " .. debug.traceback())
        end

        -- 使用配置的检测间隔，默认为5分钟
        local checkInterval = 5000
        logger.info("等待" .. 5000 .. "秒后进行下一次检测")
        mSleep(checkInterval)
        if max_limit > 10 then
            logger.info("已连续10次检测未进入地图，任务退出")
            return false
        end
    end
end

-- 通过打开地图移动指定坐标进入地图的通用函数
function Map.enterMapByPoint(map_name, level1, level2)
    level1 = level1 or 1
    level2 = level2 or 1
    local safe_zone_id = config.BOSS_MAPS[map_name].safe_zone_id
    if safe_zone_id ~= nil then
        if Map.enterSafeZoneByLevel(safe_zone_id) then
            logger.info(string.format("进入第%d层安全区：%s", safe_zone_id, map_name))
        else
            return false
        end
    end

    local map_cfg = config.BOSS_MAPS[map_name]

    logger.info("运行进入地图脚本")
    local max_limit = 0;
    while true do
        if movement.isInMZ() then
            combat.stopAutoAttack()
            movement.useTownStone()
            Map.openMap()
            movement.moveTo(map_cfg.MOVE_COORDS[1], map_cfg.MOVE_COORDS[2])
            Map.closeMap()
            tap(map_cfg.NPC_POINT[1], map_cfg.NPC_POINT[2])
            mSleep(800)
            if map_cfg.Level1_POINTS ~= nil then
                tap(map_cfg.Level1_POINTS[level1][1], map_cfg.Level1_POINTS[level1][2])
                mSleep(800)
            end

            if map_cfg.Level2_POINTS ~= nil then
                tap(map_cfg.Level2_POINTS[level2][1], map_cfg.Level2_POINTS[level2][2])
            end
            mSleep(800)
            if not movement.isInMZ() then
                logger.info("已到达" .. map_name .. "地图")
                combat.startAutoAttack()
                return true
            else
                movement.useTownStone()
            end
            logger.info(string.format("未进入%s地图", map_name))
        else
            logger.info("当前已在" .. map_name .. "中")
            return true
        end
        -- 使用配置的检测间隔，默认为5分钟
        local checkInterval = 5000
        logger.info("等待" .. 5000 .. "秒后进行下一次检测")
        mSleep(checkInterval)
        if max_limit > 3 then
            logger.info("已连续3次检测未进入地图，任务退出")
            return false
        end
    end
end

-- 根据SAFE_ZONES配置，通过传入数组下标代表进入到那层，需要一层层点击传送点
function Map.enterSafeZoneByLevel(level)
    -- 添加level参数验证，如果大于SAFE_ZONES的长度，则报错
    if level > #config.SAFE_ZONES then
        logger.error("传入的level参数超出SAFE_ZONES配置范围")
        return false
    end

    logger.info(string.format("准备进入第%d层安全区", level))
    -- 判断是否到达目标层级 如果没有到达，则回城重新执行一次，最多三次
    local max_limit = 0
    while true do
        -- 层级传送逻辑
        for i = 1, level do
            -- 进入安全区层级导航流程
            Map.openMap()
            movement.moveTo(config.SAFE_ZONES[i].ENTRY_COORDS[1], config.SAFE_ZONES[i].ENTRY_COORDS[2])
            Map.closeMap()

            tap(config.SAFE_ZONES[i].NPC_POINT[1], config.SAFE_ZONES[i].NPC_POINT[2])
            mSleep(800)
        end


        if movement.isInSafeZone(level) then
            logger.info(string.format("成功到达第%d层", level))
            break
        else
            logger.info(string.format("未到达第%d层", level))
            max_limit = max_limit + 1
            if max_limit > 3 then
                logger.error("超过最大尝试次数，退出多层安全区进入流程")
                return false
            end
            movement.useTownStone()
            mSleep(800)
        end
    end
    return true
end

-- 添加一个单个地图刷图的函数，参数是地图名称，返回值是是否成功
function Map.enterMapAndFight(map_name)
    -- 先判断是否在地图中
    local success = false
    local retry_count = 0

    -- 带重试机制的进图逻辑
    while not success and retry_count < 3 do
        logger.info(string.format("尝试进入%s（第%d次）", map_name, retry_count + 1))
        window.closeOtherWindow()
        if Map.enterMapByPoint(map_name) then
            logger.info(string.format("成功进入%s", map_name))
            -- 根据配置读取bs的坐标
            local map_cfg = config.BOSS_MAPS[map_name]

            if not map_cfg then
                logger.error(string.format("%s未配置地图信息", map_name))
                success = true
                break
            end

            if map_cfg.BOSS_TIME then
                logger.info(string.format("%s未配置boss坐标，默认刷%d分钟", map_name, map_cfg.BOSS_TIME))
                mSleep(map_cfg.BOSS_TIME * 60 * 1000)     -- 转换为毫秒
            else
                logger.warn(string.format("%s未配置boss坐标，默认刷30分钟", map_name))
                mSleep(30 * 60 * 1000)
            end
            success = true
            break
        else
            retry_count = retry_count + 1
            logger.warn("进入地图失败，等待重试")
            mSleep(5000)
        end
    end

    return success
end

return Map
